package org.alwayssuper.protostar.field;

import org.alwayssuper.protostar.Schema;
import org.alwayssuper.protostar.schema.MultiMapSchema;
import org.alwayssuper.protostar.util.Explain;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

/**
 * 多键值对字段域，每个Schema自行决定读取字节数
 * 适用于GBT32960等协议中key后面直接跟value对象的场景
 * @author alwaysSuper
 */
public class MultiMapField<K, V> extends BasicField<Map<K, V>> {

    private static final Logger log = LoggerFactory.getLogger(MultiMapField.class.getSimpleName());

    private final Schema<K> keySchema;
    private final Map<K, Schema<V>> valueSchema;
    private final boolean treeMap;

    public MultiMapField(MultiMapSchema multiMapSchema, Class typeClass) {
        this.keySchema = multiMapSchema.keySchema;
        this.valueSchema = multiMapSchema.valueSchema;
        this.treeMap = !HashMap.class.isAssignableFrom(typeClass);
    }

    @Override
    public Map<K, V> readFrom(ByteBuf input) {
        Map map;
        if (treeMap) map = new TreeMap<>();
        else map = new HashMap<>(8);

        K key = null;
        try {
            // 连续读取多个键值对，直到缓冲区读完
            while (input.isReadable()) {
                // 读取键
                key = keySchema.readFrom(input);
                
                // 根据键找到对应的Schema，让它自行决定读取多少字节
                Schema<V> schema = valueSchema.get(key);
                if (schema != null) {
                    V value = schema.readFrom(input);
                    map.put(key, value);
                } else {
                    // 如果没有找到对应的Schema，读取剩余所有字节
                    log.warn("未找到键[{}]对应的Schema，读取剩余字节", key);
                    byte[] bytes = new byte[input.readableBytes()];
                    input.readBytes(bytes);
                    map.put(key, (V) bytes);
                    break; // 读完剩余字节后退出
                }
            }
        } catch (Exception e) {
            log.warn("解析出错:KEY[{}], {}", key, e.getMessage());
        }
        return map;
    }

    @Override
    public void writeTo(ByteBuf output, Map<K, V> map) {
        if (map == null)
            return;

        for (Map.Entry<K, V> entry : map.entrySet()) {
            K key = entry.getKey();
            V value = entry.getValue();
            
            // 写入键
            keySchema.writeTo(output, key);
            
            // 根据键找到对应的Schema写入值
            Schema<V> schema = valueSchema.get(key);
            if (schema != null) {
                schema.writeTo(output, value);
            } else {
                // 如果值是字节数组，直接写入
                if (value instanceof byte[]) {
                    output.writeBytes((byte[]) value);
                } else {
                    log.warn("未注册的信息:KEY[{}], VALUE[{}]", key, value);
                }
            }
        }
    }

    @Override
    public Map<K, V> readFrom(ByteBuf input, Explain explain) {
        Map map;
        if (treeMap) map = new TreeMap<>();
        else map = new HashMap<>(8);

        K key = null;
        try {
            // 连续读取多个键值对，直到缓冲区读完
            while (input.isReadable()) {
                // 读取键
                key = keySchema.readFrom(input, explain);
                explain.setLastDesc(desc + "键");
                
                // 根据键找到对应的Schema，让它自行决定读取多少字节
                Schema<V> schema = valueSchema.get(key);
                if (schema != null) {
                    V value = schema.readFrom(input, explain);
                    map.put(key, value);
                } else {
                    // 如果没有找到对应的Schema，读取剩余所有字节
                    log.warn("未找到键[{}]对应的Schema，读取剩余字节", key);
                    int begin = input.readerIndex();
                    byte[] bytes = new byte[input.readableBytes()];
                    input.readBytes(bytes);
                    explain.readField(begin, desc + "未知数据", ByteBufUtil.hexDump(bytes), input);
                    map.put(key, (V) bytes);
                    break; // 读完剩余字节后退出
                }
            }
        } catch (Exception e) {
            log.warn("解析出错:KEY[{}], {}", key, e.getMessage());
        }
        return map;
    }

    @Override
    public void writeTo(ByteBuf output, Map<K, V> map, Explain explain) {
        if (map == null)
            return;

        for (Map.Entry<K, V> entry : map.entrySet()) {
            K key = entry.getKey();
            V value = entry.getValue();
            
            // 写入键
            keySchema.writeTo(output, key, explain);
            explain.setLastDesc(desc + "键");
            
            // 根据键找到对应的Schema写入值
            Schema<V> schema = valueSchema.get(key);
            if (schema != null) {
                schema.writeTo(output, value, explain);
            } else {
                // 如果值是字节数组，直接写入
                if (value instanceof byte[]) {
                    int begin = output.writerIndex();
                    output.writeBytes((byte[]) value);
                    explain.writeField(begin, desc + "未知数据", ByteBufUtil.hexDump((byte[]) value), output);
                } else {
                    log.warn("未注册的信息:KEY[{}], VALUE[{}]", key, value);
                }
            }
        }
    }
}